from typing import List, Union, Dict, Optional, Tuple

import requests
from bs4 import BeautifulSoup
from bs4.element import Tag
from fake_useragent import UserAgent


class Parser:
    def __init__(self):
        self.SITE_DOMAIN = "https://gitea.radium.group"
        self.REPOSITORY_LINK = "https://gitea.radium.group/radium/project-configuration"

    def get_page_tree(self, link: str) -> BeautifulSoup:
        """Получаем дерево указанной страницы с помощью BeautifulSoup"""

        ua = UserAgent()
        headers = {"User-Agent": ua.chrome}
        response = requests.get(link, headers=headers)
        tree = BeautifulSoup(response.text, "lxml")
        return tree

    def get_table_of_elements(self, tree: BeautifulSoup) -> Tag:
        """Получаем таблицу элементов со страницы"""

        table = tree.find("table", id="repo-files-table")

        if not table:
            message = "Таблица на странице не найдена"
            raise ValueError(message)

        return table

    def get_list_of_table_elements(self, table: Tag) -> List[Tag]:
        """Получаем список элементов таблицы"""

        list_of_elements = table.find("tbody").find_all("tr")
        return list_of_elements

    def check_element_is_directory(self, element: Tag) -> bool:
        """Проверяем, является ли элемент директорией"""

        is_derictory = "directory" in " ".join(element.find("svg").get("class"))
        return is_derictory

    def get_table_elements(
        self,
        file_tree: Dict[str, Union[str, Dict]],
        table: Tag,
        subfolder: Optional[str] = None,
    ) -> None:
        """Получаем элементы таблицы (ссылки и названия на папки и файлы)"""

        def parse_table_files(
            table: Tag,
            file_tree: Dict[str, Union[str, Dict]],
            list_of_table_folders: Union[List, List[Tuple]],
            subfolder: Optional[str] = None,
        ) -> None:
            """Парсим файлы таблицы"""

            list_of_elements = self.get_list_of_table_elements(table)

            for element in list_of_elements:
                file_name = element.find("a").text.strip()
                if file_name == "..":
                    continue

                file_link = self.SITE_DOMAIN + element.find("a").get("href")

                if not self.check_element_is_directory(element):
                    if subfolder:
                        if subfolder not in file_tree:
                            file_tree[subfolder] = {}
                        file_tree[subfolder][file_name] = file_link
                    else:
                        file_tree[file_name] = file_link
                else:
                    list_of_table_folders.append((file_link, file_name))

        def parse_table_folders(
            list_of_table_folders: Union[List, List[Tuple]]
        ) -> None:
            """Парсим папки таблицы"""

            for folder in list_of_table_folders:
                folder_link, folder_name = folder
                tree = self.get_page_tree(folder_link)
                table = tree.find("table", id="repo-files-table")
                self.get_table_elements(file_tree, table, folder_name)

        # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

        list_of_table_folders = []
        parse_table_files(
            table=table,
            file_tree=file_tree,
            list_of_table_folders=list_of_table_folders,
            subfolder=subfolder,
        )
        parse_table_folders(list_of_table_folders)

    def parse_file_tree(self) -> Dict[str, Union[str, Dict]]:
        """
        Парсим дерево файлов репозитория. Собираем название и ссылки папок
        и файлов.
        """

        file_tree = {}
        tree = self.get_page_tree(self.REPOSITORY_LINK)
        repository_main_table = self.get_table_of_elements(tree)
        self.get_table_elements(file_tree, repository_main_table)
        return file_tree
